﻿#if WINDOWS

using System.Diagnostics;
using System.Windows;
using System.Windows.Media.Imaging;
using KinonekoSoftware.Studio.Languages;
using KinonekoSoftware.Studio.Models.Utils;
using KinonekoSoftware.Studio.Utils;
using KinonekoSoftware.UI;
using Point = System.Windows.Point;
using Size = System.Windows.Size;

namespace KinonekoSoftware.Studio.Components
{
    public interface IImagePositionReceiver
    {
        void SetDeltaPosition(double x, double y);
        Size CanvasSize { set; }
    }

    /*
     * 1. 选择图片
     * 2. 打开图片数据
     * 3. 判断是否为大尺寸图片
     * 4.       是：  判断是否为等比例图片
     *                  用户决定是否直接使用
     *                      是：Scaling
     *                      否：Cropping
     *          否：
     *                判断是否为等比例图片
     *                      是：Scaling
     *                      否：Cropping
     * 5.
     */

    public partial class ImageEditorViewModel : IImagePositionReceiver
    {
        internal byte[]       _OriginBuffer;
        internal byte[]       _Buffer;
        internal EditMode     _Mode;
        private  MemoryStream _ms;

        private double        _rX;
        private double        _rY;
        private bool          _canExecute;
        private Size          _canvasSize;
        private Point         _deltaPosition;
        private double        _borderX;
        private double        _borderY;
        private Int32Rect     _previewCroppedRect;
        private CroppedBitmap _previewImage;
        private BitmapImage   _backgroundImage;
        private double        _borderWidth;
        private double        _borderHeight;
        private double        _scaleRatio;


        #region Avatar

        public static async Task<Result<ImageEditResult>> Avatar()
        {
            try
            {
                var r = await Ioc.Get<IStorageService>().SingleFile(FileFormat.Image);

                if (!r.IsFinished)
                {
                    return Result<ImageEditResult>.Failure;
                }

                var ext = Path.GetExtension(r.Value.Extension);
                return await AvatarCore(ext, r.Value.Buffer);
            }
            catch
            {
                await Danger(SR.Title_Notify, SR.Image_NotSupportFormat);
                return Result<ImageEditResult>.Failure;
            }
        }

        protected internal static async Task<Result<ImageEditResult>> AvatarCore(string ext, byte[] originBuffer)
        {
            Debug.Assert(originBuffer is not null);


            //
            //
            MediaInfo.Read(originBuffer, ext, out var w, out var h);


            //
            //
            var vm  = new ImageEditorViewModel();
            var min = Math.Min(w, h);
            vm.OriginalImageSize = new Size(w, h);
            vm.ScaledWidth       = 256;
            vm.ScaledHeight      = 256;
            vm.ScaleRatio        = Math.Min(256d, min) / min;



            //
            // 处理大尺寸等比例图片的问题
            if (w > 256 && w == h)
            {
                return await CroppingSquareSizeCore(originBuffer, h, w, vm);
            }


            if (w != h)
            {
                //
                // 剪裁操作，剪裁之前先将图片缩小到1080P
                var result = await Preprocessing(originBuffer, w, h);

                vm._Mode             = EditMode.Crop;
                vm._OriginBuffer     = originBuffer;
                vm._Buffer           = result.Item1;
                vm.OriginalImageSize = new Size(result.Item2, result.Item3);
                return await Ioc.Get<IDialogService>()
                                .Dialog<ImageEditResult>(vm);
            }

            //
            // 不需要裁切，直接使用
            return Result<ImageEditResult>.Success(new ImageEditResult
            {
                OriginBuffer  = null,
                ResizedBuffer = originBuffer,
                Width         = 256,
                Height        = 256,
                OriginHeight  = h,
                OriginWidth   = w,
                IsProcessed   = true,
                Mode          = EditMode.Direct,
            });
        }

        internal static async Task<Result<ImageEditResult>> CroppingSquareSizeCore(byte[] originBuffer, int w, int h, ImageEditorViewModel vm)
        {
            var triple = await Question(TitleSR.Image_ScaleOrEdit, SR.Image_ScaleOrEdit_Edit, SR.Image_ScaleOrEdit_Scale);

            if (triple == TripleSelection.Option1)
            {
                var buffer256P = await ResizeTo256P(originBuffer);
                return Result<ImageEditResult>.Success(new ImageEditResult
                {
                    OriginBuffer  = null,
                    ResizedBuffer = buffer256P,
                    Width         = 256,
                    Height        = 256,
                    OriginHeight  = h,
                    OriginWidth   = w,
                    IsProcessed   = true,
                    Mode          = EditMode.Resize,
                });
            }

            if (triple == TripleSelection.Option2)
            {
                //
                // 剪裁操作，剪裁之前先将图片缩小到1080P
                var session = await Ioc.Get<IBusyServiceEX>().BeginSession(SR.Title_Processing);
                var result  = await Preprocessing(originBuffer, w, h);

                vm._Mode             = EditMode.Crop;
                vm._OriginBuffer     = originBuffer;
                vm._Buffer           = result.Item1;
                vm.OriginalImageSize = new Size(result.Item2, result.Item3);

                session.Dispose();
                return await Ioc.Get<IDialogService>()
                                .Dialog<ImageEditResult>(vm);

            }

            return Result<ImageEditResult>.Failure;
        }

        #endregion

        #region Thumbnail

        protected internal static async Task<Result<ImageEditResult>> ThumbnailCore(string ext, byte[] originBuffer)
        {

            Debug.Assert(originBuffer is not null);


            //
            //
            MediaInfo.Read(originBuffer, ext, out var w, out var h);


            //
            //
            var vm  = new ImageEditorViewModel();
            var min = Math.Min(w, h);
            vm.OriginalImageSize = new Size(w, h);
            vm.ScaledWidth       = 640;
            vm.ScaledHeight      = 360;
            vm.ScaleRatio        = Math.Min(360d, min) / min;

            //
            // 剪裁操作，剪裁之前先将图片缩小到1080P
            var result = await Preprocessing(originBuffer, w, h);

            vm._Mode             = EditMode.Thumbnail;
            vm._OriginBuffer     = originBuffer;
            vm._Buffer           = result.Item1;
            vm.OriginalImageSize = new Size(result.Item2, result.Item3);

            //
            // 不需要裁切，直接使用
            return Result<ImageEditResult>.Success(new ImageEditResult
            {
                OriginBuffer  = originBuffer,
                ResizedBuffer = originBuffer,
                Width         = w,
                Height        = h,
                OriginHeight  = h,
                OriginWidth   = w,
                IsProcessed   = true,
                Mode          = EditMode.Thumbnail,
            });
        }



        public static async Task<Result<ImageEditResult>> Thumbnail()
        {
            try
            {
                var r = await Ioc.Get<IStorageService>().SingleFile(FileFormat.Image);

                if (!r.IsFinished)
                {
                    return Result<ImageEditResult>.Failure;
                }

                return await ThumbnailCore(r.Value.Extension, r.Value.Buffer);
            }
            catch
            {
                await Danger(SR.Title_Notify, SR.Image_NotSupportFormat);
                return Result<ImageEditResult>.Failure;
            }
        }

        #endregion


        #region Icon

        protected internal static Task<Result<ImageEditResult>> IconCore(string ext, byte[] originBuffer)
        {

            Debug.Assert(originBuffer is not null);


            //
            //
            MediaInfo.Read(originBuffer, ext, out var w, out var h);


            if (w != h)
            {
                return Task.FromResult<Result<ImageEditResult>>(Result<ImageEditResult>.Failed(SR.Image_IconRequireSquare));
            }


            if (w > 1024)
            {
                return Task.FromResult<Result<ImageEditResult>>(Result<ImageEditResult>.Failed(SR.Image_IconRequireSmall));
            }


            //
            // 不需要裁切，直接使用
            return Task.FromResult(Result<ImageEditResult>.Success(new ImageEditResult
            {
                OriginBuffer  = originBuffer,
                ResizedBuffer = null,
                Width         = w,
                Height        = h,
                OriginHeight  = h,
                OriginWidth   = w,
                IsProcessed   = true,
                Mode          = EditMode.Direct,
            }));
        }


        public static async Task<Result<ImageEditResult>> Icon()
        {
            try
            {
                var r = await Ioc.Get<IStorageService>().SingleFile(FileFormat.Image);

                if (!r.IsFinished)
                {
                    return Result<ImageEditResult>.Failure;
                }

                return await IconCore(r.Value.Extension, r.Value.Buffer);
            }
            catch
            {
                await Danger(SR.Title_Notify, SR.Image_NotSupportFormat);
                return Result<ImageEditResult>.Failure;
            }
        }

        #endregion

        #region Emoji

        protected internal static async Task<Result<ImageEditResult>> EmojiCore(string ext, byte[] originBuffer)
        {

            Debug.Assert(originBuffer is not null);


            //
            //
            MediaInfo.Read(originBuffer, ext, out var w, out var h);


            //
            //
            var vm  = new ImageEditorViewModel();
            var min = Math.Min(w, h);
            vm.OriginalImageSize = new Size(w, h);
            vm.ScaledWidth       = 640;
            vm.ScaledHeight      = 360;
            vm.ScaleRatio        = Math.Min(320d, min) / min;

            //
            // 剪裁操作，剪裁之前先将图片缩小到720P
            var result = await ResizeTo320P(originBuffer, w, h);

            vm._Mode             = EditMode.Thumbnail;
            vm._OriginBuffer     = originBuffer;
            vm._Buffer           = result.Item1;
            vm.OriginalImageSize = new Size(result.Item2, result.Item3);

            //
            // 不需要裁切，直接使用
            return Result<ImageEditResult>.Success(new ImageEditResult
            {
                OriginBuffer  = originBuffer,
                ResizedBuffer = originBuffer,
                Width         = w,
                Height        = h,
                OriginHeight  = h,
                OriginWidth   = w,
                IsProcessed   = true,
                Mode          = EditMode.Thumbnail,
            });
        }

        public static async Task<Result<ImageEditResult>> Emoji()
        {
            try
            {
                var r = await Ioc.Get<IStorageService>().SingleFile(FileFormat.Image);

                if (!r.IsFinished)
                {
                    return Result<ImageEditResult>.Failure;
                }

                return await EmojiCore(r.Value.Extension, r.Value.Buffer);
            }
            catch
            {
                await Danger(SR.Title_Notify, SR.Image_NotSupportFormat);
                return Result<ImageEditResult>.Failure;
            }
        }

        #endregion



        #region Image

        
        public static async Task<Result<IEnumerable<FastImageEditResult>>> Image(bool isMultiple = true)
        {
            try
            {
                var array = new List<FastImageEditResult>(4);
                
                if (isMultiple)
                {

                    var r = await Ioc.Get<IStorageService>().MultiFile(FileFormat.Image);

                    if (!r.IsFinished)
                    {
                        return Result<IEnumerable<FastImageEditResult>>.Failure;
                    }

                    foreach (var result in r.Value)
                    {
                        MediaInfo.Read(result.Buffer, result.Extension, out var w, out var h);
                        array.Add(new FastImageEditResult
                        {
                        
                            Id     = $"{ID.Get()}_{w}_{h}",
                            Buffer = result.Buffer,
                            Ext    = result.Extension,
                        });
                    }
                }
                else
                {

                    var r = await Ioc.Get<IStorageService>().SingleFile(FileFormat.Image);

                    if (!r.IsFinished)
                    {
                        return Result<IEnumerable<FastImageEditResult>>.Failure;
                    }

                    var buffer = r.Value.Buffer;

                    MediaInfo.Read(buffer, r.Value.Extension, out var w, out var h);

                    array.Add(new FastImageEditResult
                    {
                        Id     = $"{ID.Get()}_{w}_{h}",
                        Buffer = buffer,
                        Ext    = r.Value.Extension,
                    });
                }

                return Result<IEnumerable<FastImageEditResult>>.Success(array);

            }
            catch
            {
                await Danger(SR.Title_Notify, SR.Image_NotSupportFormat);
                return Result<IEnumerable<FastImageEditResult>>.Failure;
            }
        }


        #endregion

        private void OnInitialize()
        {
            _ms = new MemoryStream(_Buffer);
            var bi = new BitmapImage();
            bi.BeginInit();
            bi.DecodePixelWidth  = (int)OriginalImageSize.Width;
            bi.DecodePixelHeight = (int)OriginalImageSize.Height;
            bi.StreamSource      = _ms;
            bi.EndInit();
            BackgroundImage = bi;
            PreviewImage    = new CroppedBitmap(_backgroundImage, new Int32Rect(0, 0, 256, 256));
        }

        protected override void CreateValidationRules(ICollection<DialogRule> rules)
        {
        }


        protected override void ReleaseUnmanagedResources()
        {
            _Buffer = null;
            _ms.Dispose();
        }

        protected override ImageEditResult OnFinish(bool editing)
        {

            if (_Mode == EditMode.Thumbnail)
            {
                return new ImageEditResult
                {
                    OriginBuffer  = _OriginBuffer,
                    ResizedBuffer = _Buffer,
                    Height        = ScaledHeight,
                    Width         = ScaledWidth,
                    X             = (int)_rX,
                    Y             = (int)_rY,
                    IsProcessed   = false,
                    Mode          = _Mode,
                    OriginHeight  = (int)OriginalImageSize.Width,
                    OriginWidth   = (int)OriginalImageSize.Height,
                };
            }

            return new ImageEditResult
            {
                OriginBuffer  = _Buffer,
                ResizedBuffer = _Buffer,
                Height        = ScaledHeight,
                Width         = ScaledWidth,
                X             = (int)_rX,
                Y             = (int)_rY,
                IsProcessed   = false,
                Mode          = _Mode,
                OriginHeight  = (int)OriginalImageSize.Width,
                OriginWidth   = (int)OriginalImageSize.Height,
            };
        }



        public Size OriginalImageSize { get; private set; }
        public Size ScaledImageSize   { get; private set; }
        public int  ScaledWidth       { get; private set; }
        public int  ScaledHeight      { get; private set; }


        /// <summary>
        /// 获取或设置 <see cref="BackgroundImage"/> 属性。
        /// </summary>
        public BitmapImage BackgroundImage
        {
            get => _backgroundImage;
            set => SetValue(ref _backgroundImage, value);
        }

        /// <summary>
        /// 获取或设置 <see cref="PreviewImage"/> 属性。
        /// </summary>
        public CroppedBitmap PreviewImage
        {
            get => _previewImage;
            set => SetValue(ref _previewImage, value);
        }

        public double ScaleRatio
        {
            get => _scaleRatio;
            set
            {
                SetValue(ref _scaleRatio, value);
                var min = (int)Math.Min(OriginalImageSize.Width, OriginalImageSize.Height);
                ScaledWidth  = (int)(min          * value);
                ScaledHeight = (int)(min          * value);
                BorderHeight = (CanvasSize.Height / OriginalImageSize.Height) * ScaledHeight;
                BorderWidth  = (CanvasSize.Width  / OriginalImageSize.Width)  * ScaledWidth;
                SetDeltaPosition(_deltaPosition.X, _deltaPosition.Y);

                RaiseUpdated(nameof(ScaledHeight));
                RaiseUpdated(nameof(ScaledWidth));
            }
        }

        public double BorderY
        {
            get => _borderY;
            set => SetValue(ref _borderY, value);
        }

        public double BorderX
        {
            get => _borderX;
            set => SetValue(ref _borderX, value);
        }

        public double BorderHeight
        {
            get => _borderHeight;
            set => SetValue(ref _borderHeight, value);
        }

        public double BorderWidth
        {
            get => _borderWidth;
            set => SetValue(ref _borderWidth, value);
        }

        private void UpdateCroppedImage(double deltaX, double deltaY, double w1, double h1, int sw, int sh)
        {

            _rX = Math.Clamp((deltaX * w1) - (sw / 2d), 0, w1 - sw);
            _rY = Math.Clamp((deltaY * h1) - (sh / 2d), 0, h1 - sh);

            //
            // avoid to many alloc and improve performance
            //
            // _previewCroppedRect = new Int32Rect(
            //     x: croppedX,
            //     y: croppedY,
            //     width: ScaledWidth,
            //     height: ScaledHeight);
            //

            _previewCroppedRect.X      = (int)_rX;
            _previewCroppedRect.Y      = (int)_rY;
            _previewCroppedRect.Width  = sw;
            _previewCroppedRect.Height = sh;

            // PreviewImage.SourceRect = _previewCroppedRect;
            PreviewImage = new CroppedBitmap(BackgroundImage, _previewCroppedRect);
        }

        public void SetDeltaPosition(double deltaX, double deltaY)
        {
            //
            //
            _deltaPosition.X = deltaX;
            _deltaPosition.Y = deltaY;

            var w  = CanvasSize.Width;
            var h  = CanvasSize.Height;
            var w1 = OriginalImageSize.Width;
            var h1 = OriginalImageSize.Height;

            var sw    = ScaledWidth;
            var sh    = ScaledHeight;
            var bw    = BorderWidth;
            var bh    = BorderHeight;
            var halfW = bw / 2d;
            var halfH = bh / 2d;

            //
            // Update Cropped Source
            if (BackgroundImage is not null)
            {
                UpdateCroppedImage(deltaX, deltaY, w1, h1, sw, sh);
            }

            //
            // 计算边框的位置
            var x = deltaX * w;
            var y = deltaY * h;

            BorderX = Math.Clamp(x - halfW, 0, (int)(w - bw));
            BorderY = Math.Clamp(y - halfH, 0, (int)(h - bh));
        }


        /// <summary>
        /// 画布大小
        /// </summary>
        public Size CanvasSize
        {
            get => _canvasSize;
            set
            {
                if (_canExecute)
                {
                    return;
                }

                _canvasSize = value;
                _canExecute = true;


                BorderHeight    = (value.Height / OriginalImageSize.Height) * ScaledHeight;
                BorderWidth     = (value.Width  / OriginalImageSize.Width)  * ScaledWidth;
                ScaledImageSize = value;

                OnInitialize();
            }
        }

    }
}
#endif